<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>分布式锁技术详解 | 技术小馆</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        .hero-bg {
            background: linear-gradient(135deg, #6e8efb 0%, #a777e3 100%);
        }
        .prose {
            max-width: 800px;
        }
        .prose h2 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
            color: #2d3748;
            position: relative;
            padding-bottom: 0.5rem;
        }
        .prose h2:after {
            content: "";
            position: absolute;
            bottom: 0;
            left: 0;
            width: 60px;
            height: 3px;
            background: #6e8efb;
            border-radius: 3px;
        }
        .prose h3 {
            font-weight: 500;
            color: #4a5568;
        }
        .prose p {
            margin-bottom: 1.25em;
        }
        .code-block {
            background: #2d3748;
            border-radius: 8px;
            padding: 1.5rem;
            position: relative;
            overflow-x: auto;
        }
        .code-block pre {
            margin: 0;
            color: #e2e8f0;
            font-family: 'Courier New', Courier, monospace;
        }
        .code-block:before {
            content: "";
            position: absolute;
            top: 12px;
            left: 12px;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: #ff5f56;
            box-shadow: 20px 0 0 #ffbd2e, 40px 0 0 #27c93f;
        }
        .comparison-table {
            width: 100%;
            border-collapse: collapse;
            margin: 2rem 0;
        }
        .comparison-table th, .comparison-table td {
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #e2e8f0;
        }
        .comparison-table th {
            background-color: #f7fafc;
            font-weight: 600;
            color: #4a5568;
        }
        .comparison-table tr:hover {
            background-color: #f8f9fa;
        }
        .feature-icon {
            width: 48px;
            height: 48px;
            border-radius: 50%;
            background: #6e8efb;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-right: 1rem;
            flex-shrink: 0;
        }
        .visualization-container {
            background: #f7fafc;
            border-radius: 12px;
            padding: 2rem;
            margin: 3rem 0;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        .card {
            background: white;
            border-radius: 12px;
            padding: 2rem;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
            transition: all 0.3s ease;
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .step-number {
            display: inline-block;
            width: 32px;
            height: 32px;
            background: #6e8efb;
            color: white;
            border-radius: 50%;
            text-align: center;
            line-height: 32px;
            margin-right: 0.5rem;
            font-weight: bold;
        }
        .feature-item {
            display: flex;
            align-items: flex-start;
            margin-bottom: 1.5rem;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero-bg text-white py-20">
        <div class="container mx-auto px-6 flex flex-col items-center">
            <div class="text-center max-w-3xl">
                <h1 class="text-4xl md:text-5xl font-bold mb-6 leading-tight">分布式锁技术详解</h1>
                <p class="text-xl opacity-90 mb-8">在多服务架构下确保数据一致性的关键机制</p>
                <div class="flex justify-center space-x-4">
                    <a href="#why" class="px-6 py-3 bg-white text-indigo-700 rounded-lg font-medium hover:bg-opacity-90 transition duration-300">为什么需要</a>
                    <a href="#solutions" class="px-6 py-3 border-2 border-white rounded-lg font-medium hover:bg-white hover:bg-opacity-10 transition duration-300">实现方案</a>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto px-6 py-16">
        <article class="prose mx-auto">
            <!-- Why Section -->
            <section id="why" class="mb-20">
                <h2 class="text-3xl mb-6">
                    <i class="fas fa-question-circle text-indigo-500 mr-3"></i>
                    为什么需要分布式锁？
                </h2>
                <div class="flex flex-col lg:flex-row gap-8">
                    <div class="lg:w-2/3">
                        <p class="text-lg mb-6">在分布式系统中，多个服务实例可能会同时访问和修改共享资源，例如数据库、缓存等。如果没有合适的同步机制，可能会导致数据不一致、并发冲突等问题。</p>
                        <p class="text-lg mb-6">因此，我们需要一种机制来确保同一时间只有一个实例能执行关键操作，这就是分布式锁的作用。</p>
                        
                        <div class="visualization-container">
                            <div class="mermaid">
                                graph TD
                                    A[客户端1] -->|请求锁| B(分布式锁服务)
                                    C[客户端2] -->|请求锁| B
                                    B -->|授予锁| A
                                    A -->|访问资源| D[(共享资源)]
                                    A -->|释放锁| B
                                    B -->|授予锁| C
                                    C -->|访问资源| D
                            </div>
                        </div>
                    </div>
                    <div class="lg:w-1/3">
                        <div class="card">
                            <h3 class="text-xl font-semibold mb-4 text-indigo-600">典型应用场景</h3>
                            <ul class="space-y-3">
                                <li class="flex items-start">
                                    <i class="fas fa-shopping-cart text-indigo-500 mt-1 mr-2"></i>
                                    电商库存扣减
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-ticket-alt text-indigo-500 mt-1 mr-2"></i>
                                    秒杀活动抢购
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-file-invoice-dollar text-indigo-500 mt-1 mr-2"></i>
                                    金融交易处理
                                </li>
                                <li class="flex items-start">
                                    <i class="fas fa-sync-alt text-indigo-500 mt-1 mr-2"></i>
                                    定时任务调度
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Requirements Section -->
            <section id="requirements" class="mb-20">
                <h2 class="text-3xl mb-8">
                    <i class="fas fa-clipboard-check text-indigo-500 mr-3"></i>
                    分布式锁的基本要求
                </h2>
                <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
                    <div class="feature-item">
                        <div class="feature-icon">
                            <i class="fas fa-lock"></i>
                        </div>
                        <div>
                            <h3 class="font-semibold text-lg mb-1">互斥性</h3>
                            <p class="text-gray-600">同一时间只能有一个客户端获得锁</p>
                        </div>
                    </div>
                    <div class="feature-item">
                        <div class="feature-icon">
                            <i class="fas fa-skull-crossbones"></i>
                        </div>
                        <div>
                            <h3 class="font-semibold text-lg mb-1">防死锁</h3>
                            <p class="text-gray-600">即使客户端崩溃或网络异常，锁也能被释放</p>
                        </div>
                    </div>
                    <div class="feature-item">
                        <div class="feature-icon">
                            <i class="fas fa-bolt"></i>
                        </div>
                        <div>
                            <h3 class="font-semibold text-lg mb-1">高可用</h3>
                            <p class="text-gray-600">锁服务需要在高并发环境下稳定运行</p>
                        </div>
                    </div>
                    <div class="feature-item">
                        <div class="feature-icon">
                            <i class="fas fa-redo"></i>
                        </div>
                        <div>
                            <h3 class="font-semibold text-lg mb-1">可重入性</h3>
                            <p class="text-gray-600">同一个客户端如果已经持有锁，可以再次获取</p>
                        </div>
                    </div>
                    <div class="feature-item">
                        <div class="feature-icon">
                            <i class="fas fa-clock"></i>
                        </div>
                        <div>
                            <h3 class="font-semibold text-lg mb-1">超时释放</h3>
                            <p class="text-gray-600">避免锁长期不释放，导致资源被占用</p>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Solutions Section -->
            <section id="solutions" class="mb-20">
                <h2 class="text-3xl mb-8">
                    <i class="fas fa-lightbulb text-indigo-500 mr-3"></i>
                    常见的分布式锁实现方案
                </h2>

                <!-- Database Lock -->
                <div class="mb-16">
                    <h3 class="text-2xl mb-4 text-indigo-600">3.1 基于数据库的分布式锁</h3>
                    <div class="grid md:grid-cols-2 gap-8">
                        <div>
                            <h4 class="font-semibold text-lg mb-3">方案思路</h4>
                            <p>利用数据库的唯一性约束来保证同一时间只有一个线程可以获取锁。</p>
                            
                            <h4 class="font-semibold text-lg mt-6 mb-3">实现步骤</h4>
                            <div class="space-y-4">
                                <div class="flex items-start">
                                    <span class="step-number">1</span>
                                    <p>在数据库中创建一张 <code>distributed_lock</code> 表</p>
                                </div>
                                <div class="flex items-start">
                                    <span class="step-number">2</span>
                                    <p>获取锁时，插入一条唯一记录</p>
                                </div>
                                <div class="flex items-start">
                                    <span class="step-number">3</span>
                                    <p>释放锁时，删除该记录</p>
                                </div>
                            </div>
                            
                            <h4 class="font-semibold text-lg mt-6 mb-3">存在的问题</h4>
                            <ul class="list-disc pl-5 space-y-2">
                                <li>需要手动释放锁，否则可能出现死锁</li>
                                <li>数据库性能瓶颈较明显，不适用于高并发场景</li>
                            </ul>
                        </div>
                        <div>
                            <div class="code-block">
                                <pre><code>CREATE TABLE distributed_lock (
    lock_name VARCHAR(255) PRIMARY KEY,
    locked_by VARCHAR(255),
    locked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 获取锁
INSERT INTO distributed_lock (lock_name, locked_by) 
VALUES ('my_lock', 'server_1');

-- 释放锁
DELETE FROM distributed_lock 
WHERE lock_name = 'my_lock' 
AND locked_by = 'server_1';</code></pre>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Redis Lock -->
                <div class="mb-16">
                    <h3 class="text-2xl mb-4 text-indigo-600">3.2 基于 Redis 的分布式锁</h3>
                    <div class="grid md:grid-cols-2 gap-8">
                        <div>
                            <h4 class="font-semibold text-lg mb-3">方案思路</h4>
                            <p>Redis 提供了 <code>SETNX</code>（SET if Not Exists）命令，可以确保只有一个客户端能够成功获取锁。</p>
                            
                            <h4 class="font-semibold text-lg mt-6 mb-3">实现步骤</h4>
                            <div class="space-y-4">
                                <div class="flex items-start">
                                    <span class="step-number">1</span>
                                    <p>使用 <code>SETNX</code> 命令获取锁</p>
                                </div>
                                <div class="flex items-start">
                                    <span class="step-number">2</span>
                                    <p>设置锁的过期时间防止死锁</p>
                                </div>
                                <div class="flex items-start">
                                    <span class="step-number">3</span>
                                    <p>释放锁时验证请求ID防止误删</p>
                                </div>
                            </div>
                            
                            <h4 class="font-semibold text-lg mt-6 mb-3">存在的问题</h4>
                            <ul class="list-disc pl-5 space-y-2">
                                <li>需要手动处理锁超时释放</li>
                                <li>不能确保严格的互斥性，可能需要额外机制保证锁的安全性</li>
                            </ul>
                        </div>
                        <div>
                            <div class="code-block">
                                <pre><code>// 获取锁
String lockKey = "my_lock";
String requestId = UUID.randomUUID().toString();
boolean locked = redisClient.set(
    lockKey, 
    requestId, 
    "NX", 
    "PX", 
    30000
);

// 释放锁
String requestId = redisClient.get(lockKey);
if (requestId.equals(currentRequestId)) {
    redisClient.del(lockKey);
}</code></pre>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Zookeeper Lock -->
                <div class="mb-16">
                    <h3 class="text-2xl mb-4 text-indigo-600">3.3 基于 Zookeeper 的分布式锁</h3>
                    <div class="grid md:grid-cols-2 gap-8">
                        <div>
                            <h4 class="font-semibold text-lg mb-3">方案思路</h4>
                            <p>Zookeeper 提供了临时顺序节点，可以天然实现分布式锁。</p>
                            
                            <h4 class="font-semibold text-lg mt-6 mb-3">实现步骤</h4>
                            <div class="space-y-4">
                                <div class="flex items-start">
                                    <span class="step-number">1</span>
                                    <p>创建临时顺序节点</p>
                                </div>
                                <div class="flex items-start">
                                    <span class="step-number">2</span>
                                    <p>获取锁：检查是否是最小节点</p>
                                </div>
                                <div class="flex items-start">
                                    <span class="step-number">3</span>
                                    <p>释放锁：删除创建的节点</p>
                                </div>
                            </div>
                            
                            <h4 class="font-semibold text-lg mt-6 mb-3">存在的问题</h4>
                            <ul class="list-disc pl-5 space-y-2">
                                <li>依赖 Zookeeper，需要额外部署服务</li>
                                <li>性能可能不如 Redis 方案</li>
                            </ul>
                        </div>
                        <div>
                            <div class="code-block">
                                <pre><code>// 创建临时顺序节点
String lockPath = "/locks/my_lock/";
String createdPath = zookeeper.create(
    lockPath, 
    data, 
    Ids.OPEN_ACL_UNSAFE, 
    CreateMode.EPHEMERAL_SEQUENTIAL
);

// 获取锁
// 1. 查询所有子节点
// 2. 如果当前节点是最小节点，获得锁
// 3. 否则监听前一个节点

// 释放锁
zookeeper.delete(createdPath, -1);</code></pre>
                            </div>
                        </div>
                    </div>
                </div>
            </section>

            <!-- Comparison Section -->
            <section class="mb-20">
                <h2 class="text-3xl mb-8">
                    <i class="fas fa-balance-scale text-indigo-500 mr-3"></i>
                    方案选型建议
                </h2>
                <div class="overflow-x-auto">
                    <table class="comparison-table">
                        <thead>
                            <tr>
                                <th>方案</th>
                                <th>适用场景</th>
                                <th>互斥性</th>
                                <th>高可用</th>
                                <th>性能</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td><strong>数据库锁</strong></td>
                                <td>低并发，已有数据库支持</td>
                                <td>一般</td>
                                <td>高</td>
                                <td>低</td>
                            </tr>
                            <tr>
                                <td><strong>Redis 锁</strong></td>
                                <td>高并发，低延迟</td>
                                <td>一般</td>
                                <td>高</td>
                                <td>高</td>
                            </tr>
                            <tr>
                                <td><strong>Zookeeper 锁</strong></td>
                                <td>强一致性，事务性操作</td>
                                <td>高</td>
                                <td>高</td>
                                <td>中</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </section>

            <!-- Practical Section -->
            <section class="mb-20">
                <h2 class="text-3xl mb-8">
                    <i class="fas fa-code text-indigo-500 mr-3"></i>
                    实战：使用 Redis 实现分布式锁
                </h2>
                
                <h3 class="text-2xl mb-4 text-indigo-600">5.1 依赖引入</h3>
                <div class="code-block mb-8">
                    <pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.redisson&lt;/groupId&gt;
    &lt;artifactId&gt;redisson&lt;/artifactId&gt;
    &lt;version&gt;3.16.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
                </div>
                
                <h3 class="text-2xl mb-4 text-indigo-600">5.2 代码实现</h3>
                <div class="code-block mb-8">
                    <pre><code class="language-java">import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class DistributedLockExample {
    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create(config);

        RLock lock = redisson.getLock("my_lock");
        try {
            lock.lock();
            // 业务逻辑
        } finally {
            lock.unlock();
        }
    }
}</code></pre>
                </div>
                
                <h3 class="text-2xl mb-4 text-indigo-600">5.3 运行效果</h3>
                <p>当多个客户端尝试获取 <code>my_lock</code> 时，Redisson 确保同一时刻只有一个客户端持有锁。</p>
                
                <div class="visualization-container mt-8">
                    <div class="mermaid">
                        sequenceDiagram
                            participant C1 as 客户端1
                            participant C2 as 客户端2
                            participant R as Redis
                            
                            C1->>R: 获取 my_lock
                            R-->>C1: 成功获取锁
                            C2->>R: 尝试获取 my_lock
                            R-->>C2: 获取失败，等待
                            C1->>R: 释放 my_lock
                            R-->>C2: 通知锁释放
                            C2->>R: 再次尝试获取 my_lock
                            R-->>C2: 成功获取锁
                    </div>
                </div>
            </section>
        </article>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="container mx-auto px-6">
            <div class="text-center">
                <h3 class="text-xl font-semibold mb-2">技术小馆</h3>
                <p class="mb-4">分享前沿技术，探讨架构设计</p>
                <a href="http://www.yuque.com/jtostring" class="text-indigo-400 hover:text-indigo-300 transition duration-200">http://www.yuque.com/jtostring</a>
            </div>
        </div>
    </footer>

    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            },
            sequence: {
                diagramMarginX: 50,
                diagramMarginY: 10,
                actorMargin: 50,
                width: 300,
                height: 300
            }
        });
    </script>
</body>
</html>